package multi_thread.master.lock_aqs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Cheng Jun
 * Description:
 * reentrantLock 基本用法 lock()、unlock() 必须一前一后成对出现，都必须被运行，免得造成线程永久阻塞，
 * lock()、unlock() 通常在try-finally代码块里调用以保证两个方法都会被执行。
 *
 * 总结一下：synchronized 和 reentrantLock 的区别，各自的优劣势。
 * 1. synchronized jvm层面的锁，通过对象锁来实现加锁解锁，reentrantLock jdk层面的锁，通过AQS中的 state来实现加锁解锁
 * 2. synchronized 自动上锁解锁，reentrantLock 手动上锁解锁
 * 3. synchronized 非公平锁，reentrantLock 可以设置非公平锁还是公平锁
 * 4. synchronized 底层有锁升级
 * 5. synchronized reentrantLock 都是可重入锁
 * 6. reentrantLock 可以通过 condition 实现更细粒度的控制
 *
 * AQS AbstractQueuedSynchronizer 本质是一个队列，队列中放在等待锁的线程。abstract 表示该类是抽象类，queued 队列化，synchronizer 同步器
 * volatile int state 和 volatile Thread exclusiveOwnerThread /ɪkˈskluːsɪv/
 * state 同步器的状态，0时表示该同步器可用，
 * exclusiveOwnerThread 独占同步器的线程
 * @version 1.0
 * @date 2021/10/15 7:25
 * @see AbstractQueuedSynchronizer
 */
public class ReentrantLockExample {

    public static void main(String[] args) throws InterruptedException {
        ReentrantLock reentrantLock = new ReentrantLock();
        Thread thread0 = new Thread(() -> {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + "-调用reentrantLock.lock() " + "获取锁");
            try {
                TimeUnit.SECONDS.sleep(6);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                reentrantLock.unlock();
            }
        });

        Thread thread1 = new Thread(() -> {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + "-调用reentrantLock.lock() " + "获取锁");
            reentrantLock.unlock();
        });

        Thread thread2 = new Thread(() -> {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + "-调用reentrantLock.lock() " + "获取锁");
            reentrantLock.unlock();
        });

        Thread thread3 = new Thread(() -> {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + "-调用reentrantLock.lock() " + "获取锁");
            // reentrantLock.unlock();
        });

        Thread thread4 = new Thread(() -> {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + "-调用reentrantLock.lock() " + "获取锁");
            // reentrantLock.unlock();
        });

        Thread thread5 = new Thread(() -> {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + "-调用reentrantLock.lock() " + "获取锁");
            // reentrantLock.unlock();
        });

        thread0.start();
        TimeUnit.SECONDS.sleep(1);
        thread1.start();
        TimeUnit.SECONDS.sleep(1);
        thread2.start();
        TimeUnit.SECONDS.sleep(1);
        thread3.start();
        TimeUnit.SECONDS.sleep(1);
        thread4.start();
        TimeUnit.SECONDS.sleep(1);
        thread5.start();
    }
}
